package com.alibaba.otter.manager.web.service;

import com.alibaba.otter.manager.biz.common.exceptions.ManagerException;
import com.alibaba.otter.manager.biz.config.autokeeper.AutoKeeperClusterService;
import com.alibaba.otter.manager.biz.dto.CommonSearchDTO;
import com.alibaba.otter.manager.biz.config.node.NodeService;
import com.alibaba.otter.manager.biz.config.pipeline.PipelineService;
import com.alibaba.otter.manager.biz.remote.NodeRemoteService;
import com.alibaba.otter.manager.web.dto.MemoryUsageDTO;
import com.alibaba.otter.manager.web.dto.NodeDTO;
import com.alibaba.otter.manager.web.mapstruct.NodeMapper;
import com.alibaba.otter.manager.web.utils.PaginationUtil;
import com.alibaba.otter.shared.common.model.autokeeper.AutoKeeperCluster;
import com.alibaba.otter.shared.common.model.config.node.Node;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.core.paginate.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class NodeAggService {


    private final NodeService nodeService;

    private final PipelineService pipelineService;

    private final NodeRemoteService nodeRemoteService;

    private final AutoKeeperClusterService autoKeeperClusterService;

    private final NodeMapper nodeMapper;

    private final ObjectMapper objectMapper;

    public NodeAggService(NodeService nodeService, PipelineService pipelineService, NodeRemoteService nodeRemoteService, AutoKeeperClusterService autoKeeperClusterService, NodeMapper nodeMapper, ObjectMapper objectMapper) {
        this.nodeService = nodeService;
        this.pipelineService = pipelineService;
        this.nodeRemoteService = nodeRemoteService;
        this.autoKeeperClusterService = autoKeeperClusterService;
        this.nodeMapper = nodeMapper;
        this.objectMapper = objectMapper;
    }

    public Page<NodeDTO> list(CommonSearchDTO searchDTO, Pageable pageable){

        Page<Node> pages = nodeService.nodePage(searchDTO, pageable);
        List<Node> records = pages.getRecords();
        List<NodeDTO> nodes = nodeMapper.toDTO(records);
        for (NodeDTO node : nodes) {
            node.setUsed(pipelineService.hasRelation(node.getId()));
        }
        return PaginationUtil.of(nodes,pages);
    }

    public NodeDTO findById(Long nodeId) {

        Node node = nodeService.findById(nodeId);
        NodeDTO nodeDTO = nodeMapper.toDTO(node);
        if (node.getStatus().isStart()) {
            try {
                nodeDTO.setHeapMemoryUsage(objectMapper.readValue(nodeRemoteService.getHeapMemoryUsage(nodeId), MemoryUsageDTO.class));
            } catch (JsonProcessingException e) {
                throw new IllegalStateException(e);
            }
            nodeDTO.setVersionInfo(nodeRemoteService.getNodeVersionInfo(nodeId));
            nodeDTO.setSystemInfo(nodeRemoteService.getNodeSystemInfo(nodeId));
            nodeDTO.setThreadActiveSize(nodeRemoteService.getThreadActiveSize(nodeId));
            nodeDTO.setThreadPoolSize(nodeRemoteService.getThreadPoolSize(nodeId));
            nodeDTO.setRunningPipelines(nodeRemoteService.getRunningPipelines(nodeId));
        } else {
            nodeDTO.setVersionInfo("");
            nodeDTO.setSystemInfo("");
            nodeDTO.setThreadActiveSize(0);
            nodeDTO.setThreadPoolSize(0);
            nodeDTO.setRunningPipelines(null);
        }
        return nodeDTO;
    }


    public void create(Node node) {
        AutoKeeperCluster autoKeeperCluster = autoKeeperClusterService.findAutoKeeperClusterById(node.getParameters().getZkCluster().getId());
        node.getParameters().setZkCluster(autoKeeperCluster);
        nodeService.create(node);
    }


    public void modify(Node node) {
        AutoKeeperCluster autoKeeperCluster = autoKeeperClusterService.findAutoKeeperClusterById(node.getParameters().getZkCluster().getId());
        node.getParameters().setZkCluster(autoKeeperCluster);
        nodeService.modify(node);
    }


    public void delete(Long nodeId) {

        if (pipelineService.hasRelation(nodeId) || nodeService.findById(nodeId).getStatus().isStart()) {
            throw new ManagerException("node 被其他pipeline引用");
        } else {
            nodeService.remove(nodeId);
        }
    }
}
